#include "ps2_handle_spi.h"
#include "spi.h"
#include "stdio.h"

/**
 * @note        *All of the code from the Internet*
 * @reorganize: Vaine0
 * @date        2021/04/05
 **/


/**
 * @brief the test program for ps2 handle;
 * @note  using the function printf() and HAL_Delay();
 **/
void PS2_Handle_test(void)
{
	uint8_t PS2_KEY = 0;

	PS2_KEY = PS2_DataKey();
	if (PS2_KEY!=0)
  {
    // the mode
    printf("%d is light \r\n",PS2_Handle_Data[1]);
    // the button
    switch(PS2_KEY)
    {
      case PSB_SELECT: 	  printf("PSB_SELECT \r\n");    break;
      case PSB_L3:     	  printf("PSB_L3 \r\n");        break;
      case PSB_R3:        printf("PSB_R3 \r\n");        break;
      case PSB_START:   	printf("PSB_START \r\n");     break;
      case PSB_PAD_UP: 	  printf("PSB_PAD_UP \r\n");    break;
      case PSB_PAD_RIGHT:	printf("PSB_PAD_RIGHT \r\n"); break;
      case PSB_PAD_DOWN:  printf("PSB_PAD_DOWN \r\n");  break;
      case PSB_PAD_LEFT:  printf("PSB_PAD_LEFT \r\n");  break;
      case PSB_L2:      	printf("PSB_L2 \r\n");        break;
      case PSB_R2:        printf("PSB_R2 \r\n");        break;
      case PSB_L1:      	printf("PSB_L1 \r\n");        break;
      case PSB_R1:      	printf("PSB_R1 \r\n");        break;
      case PSB_TRIANGLE:	printf("PSB_TRIANGLE \r\n");  break;
      case PSB_CIRCLE:  	printf("PSB_CIRCLE \r\n");    break;
      case PSB_CROSS:   	printf("PSB_CROSS \r\n");     break;
      case PSB_SQUARE:  	printf("PSB_SQUARE \r\n");    break;
    }
    // vibretion
    if (PS2_KEY == PSB_R1)
    {
      PS2_Vibration(0xFF,0x00);
      HAL_Delay(150);
    }
    else if (PS2_KEY == PSB_L1)
    {
      PS2_Vibration(0x00,0xFF);
      HAL_Delay(100);
    }
    else
      PS2_Vibration(0x00,0x00);
  }
	// joystick
  printf(" %5d %5d %5d %5d\r\n",PS2_AnalogData(PSS_LX),PS2_AnalogData(PSS_LY),
                                PS2_AnalogData(PSS_RX),PS2_AnalogData(PSS_RY));
  HAL_Delay(100);
}


void delay_us(__IO uint32_t delay);
uint8_t PS2_ReadByte(uint8_t command);
void PS2_ReadData(uint8_t *command, uint8_t size);


uint16_t Handkey;
uint8_t Comd[2]={0x01,0x42};
uint8_t PS2_Handle_Data[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t scan[9]={0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint16_t MASK[]={
  PSB_SELECT,
  PSB_L3,
  PSB_R3 ,
  PSB_START,
  PSB_PAD_UP,
  PSB_PAD_RIGHT,
  PSB_PAD_DOWN,
  PSB_PAD_LEFT,
  PSB_L2,
  PSB_R2,
  PSB_L1,
  PSB_R1,
  PSB_GREEN,
  PSB_RED,
  PSB_BLUE,
  PSB_PINK,
  PSB_TRIANGLE,
  PSB_CIRCLE,
  PSB_CROSS,
  PSB_SQUARE
};


/**
 * @brief ps2 handle init and config;
 * @note  change the params if (other requirement)
 **/
void PS2_Init(void)
{
  uint8_t short_poll[9]={0x01,0x42,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  uint8_t enter_config[9]={0x01,0x43,0x00,0x01,0x00,0x00,0x00,0x00,0x00};
  uint8_t config[9]={0x01,0x44,0x00,0x01/*0x00*/,0x03/*0xEE*/,0x00,0x00,0x00,0x00};
  uint8_t vibration_on[5]={0x01,0x4D,0x00,0x00,0x01};
  uint8_t exit_config[9]={0x01,0x43,0x00,0x00,0x5A,0x5A,0x5A,0x5A,0x5A};
  PS2_ReadData(short_poll, 9);
  PS2_ReadData(short_poll, 9);
  PS2_ReadData(enter_config, 9);
  PS2_ReadData(config, 9);
  PS2_ReadData(vibration_on, 5);
  PS2_ReadData(exit_config, 9);
}


/**
 * @brief  get the pressed key's value; Mapping table is defined in ps2_handle.h;
 * @return 0: no key was pressed; else: the value is the pressed key;
 * @note   **Mapping table is defined in ps2_handle.h**
 **/
unsigned char PS2_DataKey(void)
{
	uint8_t index = 0;

	PS2_ClearData();
	PS2_ReadData(scan, 9);

	Handkey = (PS2_Handle_Data[4]<<8)|PS2_Handle_Data[3];
	for(index=0;index<16;index++)
	{
		if((Handkey&(1<<(MASK[index]-1)))==0)
			return index+1;
	}
	return 0;
}


/**
 * @brief get the mode of ps2 handle;
 * @return 0: red light mode; 1: green light mode or connection fail;
 **/
uint8_t PS2_RedLight(void)
{
	CS_L;
  delay_us(10);
	PS2_ReadByte(Comd[0]);
	PS2_ReadByte(Comd[1]);
	CS_H;
  delay_us(10);
	if (PS2_Handle_Data[1] == 0x73) return 0; // 0x42
	else return 1;
}


/**
 * @brief  data of joystick;
 * @param  button PSS_RX/PSS_RY/PSS_LX/PSS_LY;
 * @return the analog value
 **/
uint8_t PS2_AnalogData(uint8_t button)
{
	return PS2_Handle_Data[button];
}


/**
 * @brief clear the buffer PS2_Handle_Data[];
 **/
void PS2_ClearData()
{
  uint8_t a;
  for (a=0; a<9; a++)
    PS2_Handle_Data[a] = 0x00;
}


/**
 * @brief vibretion function, there has to be a delay after vibration (>100ms);
 * @param motor1 right motor, 0x00->OFF, else->ON;
 * @param motor2 left motor,  0x40 < motor2 < 0xFF;
 * @note  **There has to be a delay after vibration (>100ms)**
 **/
void PS2_Vibration(uint8_t motor1, uint8_t motor2)
{
  uint8_t vibration[9] = {0x01,0x42,0x00,motor1,motor2,0x00,0x00,0x00,0x00};
  PS2_ReadData(vibration, 9);
}


/**
 * @brief delay n us
 * @param delay n us
 **/
void delay_us(__IO uint32_t delay)
{
  int last, curr, val;
  int temp;

  while (delay != 0)
  {
    temp = delay > 900 ? 900 : delay;
    last = SysTick->VAL;
    curr = last - CPU_FREQUENCY_MHZ * temp;
    if (curr >= 0)
    {
      do
      {
          val = SysTick->VAL;
      }
      while ((val < last) && (val >= curr));
    }
    else
    {
      curr += CPU_FREQUENCY_MHZ * 1000;
      do
      {
          val = SysTick->VAL;
      }
      while ((val <= last) || (val > curr));
    }
    delay -= temp;
  }
}

/**
 * @brief  read a byte of data from the handle receiver
 * @param  command data/command that is sent
 * @return the data received
 * @note   the delay is necessary, maybe because the rate of the receiver is limited
 **/
uint8_t PS2_ReadByte(uint8_t command)
{
  uint8_t res = 0;
  while (HAL_SPI_TransmitReceive(&hspi2, &command, &res, 1, 100)!=0)
  {
    NULL;
  }
  delay_us(50);
  return res;
}

/**
 * @brief read size byte of data from the handle receiver
 * @param command the data that is going to be sent
 * @param size    the size of sent data
 **/
void PS2_ReadData(uint8_t *command, uint8_t size)
{
  uint8_t i;
  CS_L;
  delay_us(10);
  for (i=0; i<size; i++)
  {
    PS2_Handle_Data[i] = PS2_ReadByte(command[i]);
  }
  CS_H;
  delay_us(10);
}


/* 自定义函数 */
uint8_t PS2_Light(void)
{
  PS2_ReadData(Comd, 2);
  if (PS2_Handle_Data[1] == 0x73)
    return 0;
  else if (PS2_Handle_Data[1] == 0x41)
    return 1;
  else                                  
    return -1;
}

uint16_t PS2_KeyData()
{
  Handkey = (PS2_Handle_Data[4] << 8) | PS2_Handle_Data[3];
  return Handkey;
}
